package com.eshop.config.thread;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.Executor;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * 这是一个Spring配置类 AsyncTaskExecutePool，它实现了 AsyncConfigurer 接口，用于配置异步任务执行器（Async Task Executor）。它的主要职责是：
 *
 * 构造函数：接收一个 AsyncTaskProperties 类型的参数 config，该类通常用于封装异步任务执行器相关的配置信息，例如核心线程数、最大线程数、队列容量和存活时间等。
 *
 * getAsyncExecutor() 方法：
 *
 * 创建一个 ThreadPoolTaskExecutor 实例，这是Spring框架提供的一个可配置的线程池实现，适用于执行异步任务。
 * 根据 AsyncTaskProperties 配置的属性，设置线程池的核心线程数、最大线程数、队列容量、线程存活时间以及线程前缀名。
 * 设置拒绝策略为 CallerRunsPolicy，当线程池和队列已满，新提交的任务会被调用者所在的线程执行。
 * 最后初始化并返回该 ThreadPoolTaskExecutor 实例作为异步任务执行器。
 *
 * getAsyncUncaughtExceptionHandler() 方法：
 * 返回一个自定义的异步异常处理器，当异步方法抛出未捕获的异常时，该处理器会被调用。
 * 在异常处理器实现中，记录错误日志，包括异常消息、触发异常的方法名等信息。
 * 静态初始化块：
 *
 * 初始化日志记录器 log，使用 LoggerFactory.getLogger(Class) 方法获取该类的日志记录器，便于在类中记录日志信息。
 * 通过这个配置类，应用程序可以根据配置信息创建并配置好一个异步任务执行器，同时提供了处理异步任务执行过程中的未捕获异常的机制。
 */
@Configuration(proxyBeanMethods = false)
public class AsyncTaskExecutePool implements AsyncConfigurer
{
    private static final Logger log;
    private final AsyncTaskProperties config;
    
    public AsyncTaskExecutePool(final AsyncTaskProperties config) {
        this.config = config;
    }
    
    public Executor getAsyncExecutor() {
        final ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(this.config.getCorePoolSize());
        executor.setMaxPoolSize(this.config.getMaxPoolSize());
        executor.setQueueCapacity(this.config.getQueueCapacity());
        executor.setKeepAliveSeconds(this.config.getKeepAliveSeconds());
        executor.setThreadNamePrefix("el-async-");
        executor.setRejectedExecutionHandler((RejectedExecutionHandler)new ThreadPoolExecutor.CallerRunsPolicy());
        executor.initialize();
        return (Executor)executor;
    }
    
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return (throwable, method, objects) -> {
            AsyncTaskExecutePool.log.error("====" + throwable.getMessage() + "====", throwable);
            AsyncTaskExecutePool.log.error("exception method:" + method.getName());
        };
    }
    
    static {
        log = LoggerFactory.getLogger((Class)AsyncTaskExecutePool.class);
    }
}
